module.exports = (options, app) => {
    return async (ctx, next) => {
        try {
            ctx.cast = cast;
            await next();
        } catch (err) {
            // 获取错误状态码
            const status = err.status || 500;

            // egg-validate 在校验参数时，如果参数不合法，会抛出异常，err.status 就是 422
            if (status === 422) {
                console.log("参数校验失败", err.errors);
                ctx.helper.send(400, null, "参数校验失败");
                // ctx.helper.send(
                //     status,
                //     null,
                //     app.config.env === "prod" ? "参数有误" : err.errors
                // );
                return;
            }

            // 自定义的运行时异常
            if (err instanceof RuntimeException) {
                ctx.body = { ...err };
                return;
            }

            // 因为我们捕获了错误，相当于抑制了错误
            // 需要再触发 app error 事件，以防其他地方使用
            // 比如控制台就需要显示
            app.emit("error", err, this);

            // 如果错误码是 500，并且是生产环境，则不应该暴露错误细节
            const message =
                status === 500 && app.config.env === "prod"
                    ? "Internal Server Error"
                    : err.message;

            // 返回响应
            ctx.helper.send(status, "", message);

            // 因为已经捕获了这个错误，处理了，所以应该正常返回 200 响应
            ctx.status = 200;
        }
    };
};

class RuntimeException {
    constructor(code, message) {
        this.code = code;
        this.message = message;
    }
}

function cast(code = 500, message = "") {
    throw new RuntimeException(code, message);
}
